﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace NumbersToWords
{
    public enum NumberType
    {
        Digit,
        Binary,
        PreProcessedNumber,
        Multiplier
    }
    class Number
    {
        public int NumericalRepresentation;
        public string WordRepresentation;
        public NumberType Type;
    }
    class Program
    {
        Dictionary<string, string> m_dic3 = new Dictionary<string, string>();// բազմապատկիչ, multiplier
        Dictionary<string, string> m_dic2 = new Dictionary<string, string>();// հիմնական երկնիշ բաղադրիչներ, binary
        Dictionary<string, string> m_dic2a = new Dictionary<string, string>();// բոլոր երկնիշ թվերը (10-99), allbinary
        Dictionary<string, string> m_dic2b = new Dictionary<string, string>();// բոլոր թվերը մինչև 100, allbinary
        Dictionary<string, string> m_dic1 = new Dictionary<string, string>();// նիշ, digit

        static void Main(string[] args)
        {
            Program prg = new Program();
            prg.InitiateDictionaries();

            string strWordRepresentationOfTheNumber = prg.GetWordFromNumber("1000005");
            //"երեք հարյուր միլիոն չորս հարյուր հիսունվեց հազար ինը հարյուր տասնութ"
            // մեկ երկու երեք հինգ
            long strNumber = prg.GetNumberFromWord("երեք հարյուր մեկ միլիոն չորս հարյուր հիսունվեց հազար ինը հարյուր տասնութ");
        }

        void InitiateDictionaries()
        {
            // նիշ
            // digit
            m_dic1.Add("0", "");
            m_dic1.Add("1", "մեկ");
            m_dic1.Add("2", "երկու");
            m_dic1.Add("3", "երեք");
            m_dic1.Add("4", "չորս");
            m_dic1.Add("5", "հինգ");
            m_dic1.Add("6", "վեց");
            m_dic1.Add("7", "յոթ");
            m_dic1.Add("8", "ութ");
            m_dic1.Add("9", "ինը");

            // հիմնական երկնիշ բաղադրիչներ
            // binary
            m_dic2.Add("0", "");
            m_dic2.Add("1", "տաս");
            m_dic2.Add("2", "քսան");
            m_dic2.Add("3", "երեսուն");
            m_dic2.Add("4", "քառասուն");
            m_dic2.Add("5", "հիսուն");
            m_dic2.Add("6", "վաթսուն");
            m_dic2.Add("7", "յոթանասուն");
            m_dic2.Add("8", "ութսուն");
            m_dic2.Add("9", "իննսուն");

            // բոլոր երկնիշ թվերը, allbinary
            for (int i = 1; i <= 9; i++)
            {
                for (int j = 0; j <= 9; j++)
                {
                    string val = "";

                    if (m_dic2[i.ToString()] == "տաս" && m_dic1[j.ToString()] != "")
                        val = "տասն" + m_dic1[j.ToString()];
                    else
                        val = m_dic2[i.ToString()] + m_dic1[j.ToString()];

                    m_dic2a.Add(i.ToString() + j.ToString(), val);
                }
            }

            // բոլոր թվերը մինչև 100, allbinary
            for (int i = 1; i <= 9; i++)
            {
                m_dic2b.Add(i.ToString(), m_dic1[i.ToString()]);
            }
            for (int i = 10; i <= 99; i++)
            {
                m_dic2b.Add(i.ToString(), m_dic2a[i.ToString()]);
            }

            // բազմապատկիչ
            // multiplier
            m_dic3.Add("2", "հարյուր");
            m_dic3.Add("3", "հազար");
            m_dic3.Add("6", "միլիոն");
            m_dic3.Add("9", "միլիարդ");
            m_dic3.Add("12", "տրիլիոն");
        }

        string GetWordFromNumber(string number)
        {
            // workaround
            if (number == "0")
                return "զրո";

            if (number.Length > 16)
                return number;

            // միանիշ թվեր
            if (number.Length == 1)
                return m_dic1[number];

            // երկնիշ թվեր
            if (number.Length == 2)
            {
                // բացառություն - բացատը պետք է հանել
                // տաս բառի վերջում "ն" է ավելանում, եթե նախորդող նիշ կա, օր.՝ տասնմեկ կամ տասներկու
                if (StringContainsOnlyZeros(number))
                    return "";

                string restPart = GetWordFromNumber(number.Substring(1, number.Length - 1));
                if (restPart == "զրո")
                    restPart = "";

                string currentPart = number.Substring(0, 1);

                if (currentPart == "1" && restPart != "")
                    return m_dic2[currentPart] + "ն" + restPart; // 10
                else
                    return m_dic2[currentPart] + restPart; // բոլոր երկնիշ թվերը բացի 10 -ից
            }

            // հարյուր և ավել, մինչև մեկ հազար
            if (number.Length == 3)
            {
                string restPart = GetWordFromNumber(number.Substring(1, number.Length - 1));
                string currentPart = number.Substring(0, 1);

                if (StringContainsOnlyZeros(currentPart))
                    return restPart;

                currentPart = currentPart.TrimStart('0');
                if (currentPart == "1")
                    return "հարյուր " + restPart;

                return (m_dic1[currentPart] + " հարյուր " + restPart).TrimEnd();
            }

            // հազար և ավել, մինչև մեկ միլիոն
            if (number.Length > 3 && number.Length <= 6)
            {
                string restPart = GetWordFromNumber(number.Substring(number.Length - 3, 3));
                string currentPart = number.Substring(0, number.Length - 3);

                if (StringContainsOnlyZeros(currentPart))
                    return restPart;

                currentPart = currentPart.TrimStart('0');
                if (currentPart == "1")
                    return "հազար " + restPart;

                return (GetWordFromNumber(currentPart) + " հազար " + restPart).TrimEnd();
            }

            // մեկ միլիոն և ավել, մինչև մեկ միլիարդ
            if (number.Length > 6 && number.Length <= 9)
            {
                string restPart = GetWordFromNumber(number.Substring(number.Length - 6, 6));
                string currentPart = number.Substring(0, number.Length - 6);

                if (StringContainsOnlyZeros(currentPart))
                    return restPart;

                currentPart = currentPart.TrimStart('0');
                if (currentPart == "1")
                    return "միլիոն " + restPart;

                return (GetWordFromNumber(currentPart) + " միլիոն " + restPart).TrimEnd();

            }

            // մեկ միլիարդ և ավել, մինչև մեկ տրիլիոն
            if (number.Length > 9 && number.Length <= 12)
            {
                string restPart = GetWordFromNumber(number.Substring(number.Length - 9, 9));
                string currentPart = number.Substring(0, number.Length - 9);

                if (StringContainsOnlyZeros(currentPart))
                    return restPart;

                currentPart = currentPart.TrimStart('0');
                if (currentPart == "1")
                    return "միլիարդ " + restPart;

                return (GetWordFromNumber(currentPart) + " միլիարդ " + restPart).TrimEnd();
            }

            // մեկ տրիլիոն և ավել
            if (number.Length > 12)
            {
                string restPart = GetWordFromNumber(number.Substring(number.Length - 9, 9));
                string currentPart = number.Substring(0, number.Length - 9);

                if (StringContainsOnlyZeros(currentPart))
                    return restPart;

                currentPart = currentPart.TrimStart('0');

                if (currentPart == "1")
                    return "տրիլիոն " + restPart;
                else
                    return (GetWordFromNumber(currentPart) + " տրիլիոն " + restPart).TrimEnd();
            }

            return "";
        }

        string[] GetNumberFromWord_PreProcess(string[] arr)
        {
            // հայտնաբերել հարյուր բառը պարունակող 3 տիպի կառուցվածքներ
            // 1. d հարյուր b
            // 2. d հարյուր
            // 3. հարյուր b
            // 4. հարյուր
            //
            // d նիշ m_dic1
            // b բոլոր թվերը մինչև 100 m_dic2b

            //  1. d հարյուր b
            for (int i = 0; i < arr.Length - 2; i++)
            {
                if (m_dic1.ContainsValue(arr[i]) && arr[i + 1] == "հարյուր" && m_dic2b.ContainsValue(arr[i + 2]))
                {
                    arr[i] = (Convert.ToInt32(GetKeyByValue(arr[i], m_dic1)) * 100 + Convert.ToInt32(GetKeyByValue(arr[i + 2], m_dic2b))).ToString();
                    arr[i + 1] = "";
                    arr[i + 2] = "";
                }
            }

            // 2. d հարյուր
            for (int i = 0; i < arr.Length - 1; i++)
            {
                if (m_dic1.ContainsValue(arr[i]) && arr[i + 1] == "հարյուր")
                {
                    arr[i] = (Convert.ToInt32(GetKeyByValue(arr[i], m_dic1)) * 100).ToString();
                    arr[i + 1] = "";
                }
            }

            // 3. հարյուր b
            for (int i = 0; i < arr.Length - 1; i++)
            {
                if (arr[i] == "հարյուր" && m_dic2b.ContainsValue(arr[i + 1]))
                {
                    arr[i] = (100 + Convert.ToInt32(GetKeyByValue(arr[i + 1], m_dic2b))).ToString();
                    arr[i + 1] = "";
                }
            }

            // 4. հարյուր
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == "հարյուր")
                {
                    arr[i] = "100";
                }
            }

            List<string> lst = new List<string>();
            foreach (string str in arr)
            {
                if (str != "")
                    lst.Add(str);
            }

            return lst.ToArray();
        }
        long GetNumberFromWord(string word)
        {
            long number = -1;
            string[] arr = word.Split(' ');

            // Թվականը սխալ է մուտքագրված: Ամենայն հավանակությամբ այն իրենից ներկայացնում է միանիշ կամ երկնիշ թվերի հաջորդականություն: Օր. տսնվեց քսանութ
            // ծրագիրը նախատեսում է մուտքագրման 2 տարբերակ՝ միանիշներով և երկնիշերով: Օր.՝ «մեկ հինգ ինն զրո» կամ «տասնհինգ իննսուն»: Խառնված տարբերակները չեն աշխատելու
            if (!CheckIfNumberIsLitracy(arr))
            {
                //arr = RemoveSpacesBetweenBinaryNumbers(arr);

                // մուտք միանիշներով - բոլոր թվերը պետք է լինեն միանիշներ
                bool bNumberContainsOnlyDigits = true;
                foreach (string str in arr)
                {
                    if (!m_dic2.ContainsValue(str))
                        bNumberContainsOnlyDigits = false;
                }

                // մուտք երկնիշերով - բոլոր թվերը պետք է լինեն երկնիշ
                bool bNumberContainsOnlyBinary = true;
                foreach (string str in arr)
                {
                    if (!m_dic2b.ContainsValue(str))
                        bNumberContainsOnlyBinary = false;
                }

                if (bNumberContainsOnlyDigits && bNumberContainsOnlyBinary)
                    return -1;

                if (bNumberContainsOnlyDigits)
                {
                    string strRet = "";

                    foreach (string str in arr)
                    {
                        strRet += GetKeyByValue(str, m_dic1);
                    }
                    
                    Int64.TryParse(strRet, out number);
                }

                if (bNumberContainsOnlyBinary)
                {
                    string strRet = "";

                    foreach (string str in arr)
                    {
                        strRet += GetKeyByValue(str, m_dic2b);
                    }

                    Int64.TryParse(strRet, out number);
                }
                return number;
            }

            // Թվականը գրական է
            arr = GetNumberFromWord_PreProcess(arr);

            for (int i = 0; i < arr.Length; i++)
            {
                Number nmbr_current = GetNumber(arr[i]);

                // ստուգել թվին հետևող հաջորդ բազմապատկիչը
                if (nmbr_current.Type != NumberType.Multiplier)
                {
                    Number nmbr_next;
                    if (
                        i + 1 < arr.Length &&
                        (nmbr_next = GetNumber(arr[i + 1])).Type == NumberType.Multiplier
                        )
                    {
                        number += nmbr_current.NumericalRepresentation * (long)Math.Pow(10, nmbr_next.NumericalRepresentation);
                        i++;
                    }

                    else
                        number += nmbr_current.NumericalRepresentation;
                }
                else
                {
                    number += (long)Math.Pow(10, nmbr_current.NumericalRepresentation);
                }
            }
            return number;
        }

        // Helper function
        bool StringContainsOnlyZeros(string str)
        {
            foreach (var chr in str)
                if (chr != '0')
                    return false;

            return true;
        }
        string GetKeyByValue(string strValue, Dictionary<string, string> dic)
        {
            foreach (KeyValuePair<string, string> pair in dic)
            {
                if (pair.Value == strValue)
                    return pair.Key;
            }
            return "";
        }
        Number GetNumber(string strIn)
        {
            Number nmbr = new Number();

            //if (strIn == "տասն")
            //    strIn = "տաս";

            int nOut = -1;
            if (Int32.TryParse(strIn, out nOut))
            {
                nmbr.NumericalRepresentation = nOut;
                nmbr.Type = NumberType.PreProcessedNumber;
                return nmbr;
            }

            var tmp = GetKeyByValue(strIn, m_dic1);
            if (tmp != "")
            {
                nmbr.NumericalRepresentation = Int32.Parse(tmp);
                nmbr.WordRepresentation = strIn;
                nmbr.Type = NumberType.Digit;
                return nmbr;
            }

            tmp = GetKeyByValue(strIn, m_dic2a);
            if (tmp != "")
            {
                nmbr.NumericalRepresentation = Int32.Parse(tmp);
                nmbr.WordRepresentation = strIn;
                nmbr.Type = NumberType.Binary;
                return nmbr;
            }

            tmp = GetKeyByValue(strIn, m_dic3);
            if (tmp != "")
            {
                nmbr.NumericalRepresentation = Int32.Parse(tmp);
                nmbr.WordRepresentation = strIn;
                nmbr.Type = NumberType.Multiplier;
                return nmbr;
            }

            return nmbr;
        }
        bool CheckIfNumberIsLitracy(string[] arr)
        {
            if (arr.Length == 1)
                return true;

            foreach (string str in arr)
            {
                if (m_dic3.ContainsValue(str))
                    return true;
            }

            return false;
        }
    }
}
